/**********************************************************************
 *                                                                    *
 * tgt - Tiny Graphics Toolbox                                        *
 *                                                                    *
 * Copyright (C) 2006-2008 Visualization and Computer Graphics Group, *
 * Department of Computer Science, University of Muenster, Germany.   *
 * <http://viscg.uni-muenster.de>                                     *
 *                                                                    *
 * This file is part of the tgt library. This library is free         *
 * software; you can redistribute it and/or modify it under the terms *
 * of the GNU Lesser General Public License version 2.1 as published  *
 * by the Free Software Foundation.                                   *
 *                                                                    *
 * This library is distributed in the hope that it will be useful,    *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of     *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the       *
 * GNU Lesser General Public License for more details.                *
 *                                                                    *
 * You should have received a copy of the GNU Lesser General Public   *
 * License in the file "LICENSE.txt" along with this library.         *
 * If not, see <http://www.gnu.org/licenses/>.                        *
 *                                                                    *
 **********************************************************************/

#include "tgt/navigation/trackball.h"
#include "tgt/texturemanager.h"
#include "tgt/texture.h"
#include "tgt/toolkitfactory.h"
#include "tgt/guiapplication.h"
#include "tgt/glcanvas.h"
#include "tgt/painter.h"

using namespace tgt;

// Painter declaration

class TexturePainter : public Painter {
private:
    Texture* myTexture_;
    vec2 texKoord_[4]; 

public:
    TexturePainter(GLCanvas* canvas);
    ~TexturePainter();
    virtual void init();
    virtual void paint();
    virtual void sizeChanged(const ivec2& size);
};

// Painter implementation

TexturePainter::TexturePainter(GLCanvas* canvas) : Painter( canvas ) {}

TexturePainter::~TexturePainter(){
    // dispose all textures before TexMgr will be destroyed
    TexMgr.dispose( myTexture_ );
}

void TexturePainter::init(){
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_SMOOTH);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);

    // set Camera
    getCamera()->setPosition(vec3(0.f,0.f,3.f));

    // Addind pathes to look for texture files
    TexMgr.addPath("data/textures");
	TexMgr.addPath("../../samples/data/textures");

    // load Texture and specify part that will be used for texturing
    myTexture_ = TexMgr.load( "texture16x16.jpg" );
    if ( myTexture_ == NULL) std::cout << "Failed to open texture file." << std::endl;
    
    texKoord_[0] = vec2( 0.f, 0.f );
    texKoord_[1] = vec2( 1.f, 0.f );
    texKoord_[2] = vec2( 1.f, 1.f );
    texKoord_[3] = vec2( 0.f, 1.f );    
}


void TexturePainter::paint() {
    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
    getCamera()->look();
    
    // activate this texture to be used
    if ( myTexture_ ) {
        myTexture_->enable();
        myTexture_->bind();
            
        // we'll create two rows of 4 squares each with the same 
        // texture but different filtering options for demonstration

        // 1st row
        myTexture_->setWrapping(Texture::REPEAT);
        myTexture_->setFilter(Texture::LINEAR);
        glBegin(GL_QUADS);
            /* Bottom Left Of The Texture and Quad */
            glTexCoord2f(texKoord_[0].x, texKoord_[0].y); glVertex3i( -2,  0, 0 );
            /* Bottom Right Of The Texture and Quad */
            glTexCoord2f(texKoord_[1].x, texKoord_[1].y); glVertex3i( -1,  0, 0 );
            /* Top Right Of The Texture and Quad */
            glTexCoord2f(texKoord_[2].x, texKoord_[2].y); glVertex3i( -1,  1, 0 );
            /* Top Left Of The Texture and Quad */
            glTexCoord2f(texKoord_[3].x, texKoord_[3].y); glVertex3i( -2,  1, 0 );
        glEnd();
        
        myTexture_->setFilter(Texture::NEAREST);
        glBegin(GL_QUADS);
            glTexCoord2f(texKoord_[0].x, texKoord_[0].y); glVertex3i( -1,  0, 0 );
            glTexCoord2f(texKoord_[1].x, texKoord_[1].y); glVertex3i(  0,  0, 0 );
            glTexCoord2f(texKoord_[2].x, texKoord_[2].y); glVertex3i(  0,  1, 0 );
            glTexCoord2f(texKoord_[3].x, texKoord_[3].y); glVertex3i( -1,  1, 0 );
        glEnd();
        
        myTexture_->setFilter(Texture::MIPMAP);
        glBegin(GL_QUADS);
            glTexCoord2f(texKoord_[0].x, texKoord_[0].y); glVertex3i(  0,  0, 0 );
            glTexCoord2f(texKoord_[1].x, texKoord_[1].y); glVertex3i(  1,  0, 0 );
            glTexCoord2f(texKoord_[2].x, texKoord_[2].y); glVertex3i(  1,  1, 0 );
            glTexCoord2f(texKoord_[3].x, texKoord_[3].y); glVertex3i(  0,  1, 0 );
        glEnd();
        
        myTexture_->setFilter(Texture::ANISOTROPIC);
        glBegin(GL_QUADS);
            glTexCoord2f(texKoord_[0].x, texKoord_[0].y); glVertex3i(  1,  0, 0 );
            glTexCoord2f(texKoord_[1].x, texKoord_[1].y); glVertex3i(  2,  0, 0 );
            glTexCoord2f(texKoord_[2].x, texKoord_[2].y); glVertex3i(  2,  1, 0 );
            glTexCoord2f(texKoord_[3].x, texKoord_[3].y); glVertex3i(  1,  1, 0 );
        glEnd();
        
        // 2nd row
        myTexture_->setWrapping(Texture::CLAMP);
        myTexture_->setFilter(Texture::LINEAR);
        glBegin(GL_QUADS);
            glTexCoord2f(texKoord_[0].x, texKoord_[0].y); glVertex3i( -2, -1, 0 );
            glTexCoord2f(texKoord_[1].x, texKoord_[1].y); glVertex3i( -1, -1, 0 );
            glTexCoord2f(texKoord_[2].x, texKoord_[2].y); glVertex3i( -1,  0, 0 );
            glTexCoord2f(texKoord_[3].x, texKoord_[3].y); glVertex3i( -2,  0, 0 );
        glEnd();
        
        myTexture_->setFilter(Texture::NEAREST);
        glBegin(GL_QUADS);
            glTexCoord2f(texKoord_[0].x, texKoord_[0].y); glVertex3i( -1, -1, 0 );
            glTexCoord2f(texKoord_[1].x, texKoord_[1].y); glVertex3i(  0, -1, 0 );
            glTexCoord2f(texKoord_[2].x, texKoord_[2].y); glVertex3i(  0,  0, 0 );
            glTexCoord2f(texKoord_[3].x, texKoord_[3].y); glVertex3i( -1,  0, 0 );
        glEnd();
        
        myTexture_->setFilter(Texture::MIPMAP);
        glBegin(GL_QUADS);
            glTexCoord2f(texKoord_[0].x, texKoord_[0].y); glVertex3i(  0, -1, 0 );
            glTexCoord2f(texKoord_[1].x, texKoord_[1].y); glVertex3i(  1, -1, 0 );
            glTexCoord2f(texKoord_[2].x, texKoord_[2].y); glVertex3i(  1,  0, 0 );
            glTexCoord2f(texKoord_[3].x, texKoord_[3].y); glVertex3i(  0,  0, 0 );
        glEnd();
        
        myTexture_->setFilter(Texture::ANISOTROPIC);
        glBegin(GL_QUADS);
            glTexCoord2f(texKoord_[0].x, texKoord_[0].y); glVertex3i(  1, -1, 0 );
            glTexCoord2f(texKoord_[1].x, texKoord_[1].y); glVertex3i(  2, -1, 0 );
            glTexCoord2f(texKoord_[2].x, texKoord_[2].y); glVertex3i(  2,  0, 0 );
            glTexCoord2f(texKoord_[3].x, texKoord_[3].y); glVertex3i(  1,  0, 0 );
        glEnd();
    }
    else
        std::cout << "No texture available." << std::endl;
}

void TexturePainter::sizeChanged(const ivec2& size) {
    glViewport(0,0,size.x,size.y);
    getCamera()->setRatio((float) size.x/size.y);
}

// main routine

int main(int argc, char** argv) {
    
    std::cout
        << "tgt Sample Program: textures" << std::endl
        << std::endl
        << "Demonstrates loading of textures in tgt.                                        " << std::endl
        << std::endl;
    
    GUIApplication* tgtApp = ToolkitFactory::createApplication( argc, argv );    
    GLCanvas* GLCanvas = ToolkitFactory::createCanvas("tgt Example: Textures");
    tgtApp->addCanvas( GLCanvas );
    tgtApp->init();

    Camera camera;
    GLCanvas->setCamera( &camera );

    TexturePainter* painter = new TexturePainter( GLCanvas );
    GLCanvas->setPainter( painter );

    Trackball trackball( GLCanvas );
    
    GLCanvas->getEventHandler()->addListenerToFront( &trackball );
    
    tgtApp->run();
    
    delete painter;
    delete GLCanvas;
    delete tgtApp;
    
    return 0;
}
